use std::{sync::Arc, time::Duration};

use futures::{executor::block_on, pin_mut, select, FutureExt};
use tokio::{sync, task};

pub struct Timer {
    bar: Arc<sync::Barrier>,
    _tx: sync::oneshot::Sender<()>,
}

impl Timer {
    pub fn new(period: Duration) -> Self {
        let bar = Arc::new(sync::Barrier::new(2));
        let (tx, rx) = sync::oneshot::channel();

        let bar1 = bar.clone();
        std::thread::spawn(move || {
            let bar = bar1;

            block_on(async move {
                let rx_fut = rx.fuse();
                pin_mut!(rx_fut);

                loop {
                    select! {
                        _ = bar.wait().fuse() => {
                            task::block_in_place(|| {spin_sleep::sleep(period);}) ;
                        }

                        _ = rx_fut => {
                            break;
                        }
                    }
                }
            });
        });

        Self { bar, _tx: tx }
    }

    pub async fn step(&self) {
        self.bar.wait().await;
    }
}
